package mirrormonkey.state.tools.notification.listeners;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;

import java.util.Deque;
import java.util.LinkedList;

import mirrormonkey.framework.ConnectionInfo;
import mirrormonkey.framework.entity.EntityData;
import mirrormonkey.framework.entity.StaticEntityData;
import mirrormonkey.framework.entity.SyncEntity;
import mirrormonkey.state.StateUpdateListener;
import mirrormonkey.state.messages.StateUpdateMessage;

import com.jme3.network.MessageConnection;

public class MockStateUpdateListener implements StateUpdateListener {

	public final Deque<StateUpdateEvent> events = new LinkedList<StateUpdateEvent>();

	public static class StateUpdateEvent {

		@Override
		public boolean equals(Object o) {
			if (o == null) {
				return false;
			}
			if (o.getClass().equals(getClass())) {
				return true;
			}
			return false;
		}

	}

	public static class BeforeInboundEvent extends StateUpdateEvent {

		public MessageConnection from;

		public SyncEntity entity;

		public BeforeInboundEvent(MessageConnection from, SyncEntity entity) {
			this.from = from;
			this.entity = entity;
		}

		@Override
		public boolean equals(Object o) {
			if (super.equals(o)) {
				BeforeInboundEvent other = (BeforeInboundEvent) o;
				return other.from == from && other.entity == entity;
			}
			return false;
		}

	}

	public static class AfterInboundEvent extends StateUpdateEvent {

		public MessageConnection from;

		public SyncEntity entity;

		public AfterInboundEvent(MessageConnection from, SyncEntity entity) {
			this.from = from;
			this.entity = entity;
		}

		@Override
		public boolean equals(Object o) {
			if (super.equals(o)) {
				AfterInboundEvent other = (AfterInboundEvent) o;
				return other.from == from && other.entity == entity;
			}
			return false;
		}

	}

	public static class BeforeOutboundEvent extends StateUpdateEvent {

		public SyncEntity entity;

		public BeforeOutboundEvent(SyncEntity entity) {
			this.entity = entity;
		}

		@Override
		public boolean equals(Object o) {
			if (super.equals(o)) {
				BeforeOutboundEvent other = (BeforeOutboundEvent) o;
				return other.entity == entity;
			}
			return false;
		}

	}

	public static class AfterOutboundEvent extends StateUpdateEvent {

		public SyncEntity entity;

		public AfterOutboundEvent(SyncEntity entity) {
			this.entity = entity;
		}

		@Override
		public boolean equals(Object o) {
			if (super.equals(o)) {
				AfterOutboundEvent other = (AfterOutboundEvent) o;
				return other.entity == entity;
			}
			return false;
		}

	}

	public void expectEvent(StateUpdateEvent e) {
		StateUpdateEvent pe = events.pollFirst();
		assertNotNull(pe);
		assertEquals(e, pe);
	}

	public void clear() {
		events.clear();
	}

	public void addEvent(StateUpdateEvent e) {
		events.add(e);
	}

	@Override
	public void beforeInboundUpdate(ConnectionInfo inboundFrom,
			StateUpdateMessage message, EntityData entityData,
			StaticEntityData staticEntityData) {
		addEvent(new BeforeInboundEvent(inboundFrom.connection,
				entityData.entity));
	}

	@Override
	public void afterInboundUpdate(ConnectionInfo inboundFrom,
			StateUpdateMessage message, EntityData entityData,
			StaticEntityData staticEntityData) {
		addEvent(new AfterInboundEvent(inboundFrom.connection,
				entityData.entity));
	}

	@Override
	public void beforeOutboundUpdate(EntityData i, StaticEntityData staticData,
			StateUpdateMessage message) {
		addEvent(new BeforeOutboundEvent(i.entity));
	}

	@Override
	public void afterOutboundUpdate(EntityData i, StaticEntityData staticData,
			StateUpdateMessage message) {
		addEvent(new AfterOutboundEvent(i.entity));
	}

}
